/**
 * 引入内容
 */
import axios, { AxiosResponse, AxiosError } from 'axios'
// @ts-ignore
import { v4 } from 'uuid'
import { Message, Modal } from '@arco-design/web-vue'
import '@arco-design/web-vue/es/message/style/css.js'
import storage from '@/utils/storage'
import { refreshTokenMethod } from '@/api/login'
// import { useRouter } from 'vue-router';
import qs from 'query-string'
import { handleRefreshToken } from '@/api/index'

// const router = useRouter();
const refreshToken = getTokenDebounce()
// // 数据返回的接口
// // 定义请求响应参数，不含data
// interface Result {
//   code: number;
//   message: string;
//   success: string;
//   timestamp: number;
//   result: any;
// }

// /**
//  * 定义请求约束
//  */
// interface RequestRule {
//   needToken: boolean;
// }

/**
 * 请求头部
 */
interface requestHeaderRule {
  uuid?: null | string | number
  accessToken?: string
  token?: string
  appId?: string
}

// 清空并重新登录
function cleanStorage() {
  storage.setAccessToken('')
  storage.setRefreshToken('')
  storage.setUuid('')
  // router.push({
  //   path: '/Login',
  //   query: {
  //     redirect: '',
  //   },
  // });
  let currentURL = window.location.pathname + window.location.search
  if (window.location.search) {
    let data = window.location.search
      .substring(1)
      .split('&')
      .map((item) => {
        return item.split('=')
      })
    let data2 = JSON.stringify(Object.fromEntries(data))
    storage.clearToken()
    storage.clearUserInfo()
    window.location.href = `/Login?rePath=${window.location.pathname}&query=${data2}`
  } else {
    storage.clearToken()
    storage.clearUserInfo()
    window.location.href = `/Login?rePath=${window.location.pathname}`
  }
}

/**
 * 设置公有的api
 */
export const commonUrl: string =
  process.env.NODE_ENV === 'development' ? ENV.BASE.API_DEV.gateway : ENV.BASE.API_PROD.gateway
export const gatewayUrl: string =
  (process.env.NODE_ENV === 'development' ? ENV.BASE.API_DEV.gateway : ENV.BASE.API_PROD.gateway) + ENV.BASE.PREFIX

/**
 * 请求失败后的错误统一处理
 */
const errorTips = (status: number, msg: string) => {
  console.log('请求失败后的错误统一处理', status, msg)
  // 状态码判断
  switch (status) {
    case 302:
      Message.error('接口重定向了！')
      break
    case 400:
      Message.error(msg)
      break
    case 401: // 重定向
      Message.error(`token:登录失效 ==>${status}:`)
      // refresh(msg);
      break
    // 403 token过期
    // 清除token并跳转登录页
    case 403:
      Message.error(msg)
      break
    case 404:
      Message.error(`网络请求不存在 ==> ${status}`)
      break
    case 406:
      Message.error(`请求的格式不可得 ==> ${status}`)
      break
    case 408:
      Message.error('请求超时！')
      break
    case 410:
      Message.error(`请求的资源被永久删除，且不会再得到的==>${status}`)
      break
    case 422:
      Message.error(`当创建一个对象时，发生一个验证错误==>${status}`)
      break
    case 500:
      Message.error(msg)
      break
    case 502:
      Message.error(`网关错误 ==>${status}`)
      break
    case 503:
      Message.error(`服务不可用，服务器暂时过载或维护 ==>${status}`)
      break
    case 504:
      Message.error(`网关超时 ==>${status}`)
      break
    default:
      Message.error(msg)
  }
}

async function refresh(error) {
  const getTokenRes = await refreshToken()
  if (getTokenRes === 'success') {
    // 刷新token
    if (isRefreshToken === 1) {
      error.response.config.headers.accessToken = storage.getAccessToken()
      return service(error.response.config)
    } else {
      router.go(0)
    }
  } else {
    storage.setAccessToken(null)
    storage.setRefreshToken(null)
    storage.setUserInfo(null)
    storage.setCartNum(0)
    Modal.confirm({
      title: '请登录',
      content: `请登录后执行此操作`,
      okButtonProps: { type: 'primary', status: 'danger' },
      okText: '立即登录',
      cancelText: '继续浏览',
      onOk: () => {
        console.log('立即登录', router.currentRoute.value.path, router.currentRoute.value)
        router.push({
          path: '/Login',
          query: { rePath: router.currentRoute.value.path, query: JSON.stringify(router.currentRoute.value.query) }
        })
      },
      onCancel: () => {
        router.push('/user/home')
      }
    })
  }
}

/**
 * 刷新token
 */

let isRefreshing = false
// 重试队列
let requests: any = []

/**
 * 创建axios
 */
const service = axios.create({
  timeout: ENV.TIMEOUT, // 请求超时时间
  baseURL: gatewayUrl // API
})

// request拦截器
service.interceptors.request.use(
  (config: any) => {
    // 如果是put/post请求，用qs.stringify序列化参数
    const isPutPost = config.method === 'put' || config.method === 'post'
    const isJson = config.headers['Content-Type'] === 'application/json'
    const isFile = config.headers['Content-Type'] === 'multipart/form-data'
    if (isPutPost && isJson) {
      config.data = JSON.stringify(config.data)
    }
    if (isPutPost && !isFile && !isJson) {
      config.data = qs.stringify(config.data, {
        arrayFormat: 'repeat'
      })
    }

    let uuid = storage.getUuid()
    if (!uuid) {
      uuid = v4()
      storage.setUuid(uuid)
    }

    const requestHeader: requestHeaderRule = {
      uuid,
      appId: 'wxc81a593a95cf5c19'
    }

    // 获取访问Token
    const accessToken = storage.getAccessToken()
    if (config?.needToken) {
      if (accessToken) {
        requestHeader.token = accessToken
      } else {
        cleanStorage()
        return Promise.reject(new Error('未获取到accessToken，请重新登录'))
      }
    }
    config.headers = { ...config.headers, ...requestHeader }
    return config
  },
  (error: AxiosError) => {
    Promise.reject(error)
  }
)

/**
 * response 拦截器
 * 状态码正常 返回接口数据
 * 状态码异常 返回接口数据 + 头部信息
 */
service.interceptors.response.use(
  async (response: AxiosResponse) => {
    return response
  },
  async (error) => {
    const { response } = error
    const token: any = storage.getAccessToken()
    if ((token && response.data && response.data.status === 403) || response.data.status === 403) {
      if (!isRefreshing) {
        isRefreshing = true
        // 调用刷新接口
        return refreshTokenMethod(token)
          .then((res) => {
            // @ts-ignore
            const { accessToken, refreshToken } = res.data?.result
            storage.setAccessToken(accessToken)
            storage.setRefreshToken(refreshToken)
            response.headers.accessToken = `${accessToken}`
            requests.forEach((cb: any) => cb(accessToken))
            requests = [] // 重新请求完清空

            return service.request(response.config)
          })
          .catch((err) => {
            cleanStorage()
            return Promise.reject(err)
          })
          .finally(() => {
            isRefreshing = false
          })
      }
    } // 如果当前返回没登录
    if (response.status === 401 || response.data.code === 401) {
      // token过期
      if (!isRefreshing) {
        isRefreshing = true
        // 调用刷新接口
        refreshTokenMethod(token)
          .then((res) => {
            // @ts-ignore
            const { accessToken, refreshToken } = res.data?.result
            storage.setAccessToken(accessToken)
            storage.setRefreshToken(refreshToken)
            response.headers.accessToken = `${accessToken}`
            requests.forEach((cb: any) => cb(accessToken))
            requests = [] // 重新请求完清空

            return service.request(response.config)
          })
          .catch((err) => {
            cleanStorage()
            return Promise.reject(err)
          })
          .finally(() => {
            isRefreshing = false
          })
      }
    } else if (
      (!token && !storage.getRefreshToken() && response.status === 403) ||
      response.data.code === 403 ||
      response.data.code === 20004 ||
      response.data.code === 20003
    ) {
      cleanStorage()
    } else if ((response.status == 200 && !response.data.success) || response.status == 400) {
      if (response.data.message) {
        errorTips(response.data.code, response.data.message)
      }
    }
    return error
  }
)

export const Method = {
  GET: 'get',
  POST: 'post',
  PUT: 'put',
  DELETE: 'delete'
}

/**
 * 抛出request
 * @param options
 * @returns
 */
export default function request(options: object): Promise<AxiosResponse> {
  return service(options)
}

// 防抖闭包来一波
function getTokenDebounce() {
  let lock = false
  let success = false
  return function () {
    if (!lock) {
      lock = true
      let oldRefreshToken = storage.getRefreshToken()
      handleRefreshToken(oldRefreshToken)
        .then((res) => {
          if (res.data.success) {
            let { accessToken, refreshToken } = res.data.result
            storage.setAccessToken(accessToken)
            storage.setRefreshToken(refreshToken)
            success = true
            lock = false
          } else {
            success = false
            lock = false
            // router.push('/login')
          }
        })
        .catch((err) => {
          success = false
          lock = false
        })
    }
    return new Promise((resolve) => {
      // 一直看lock,直到请求失败或者成功
      const timer = setInterval(() => {
        if (!lock) {
          clearInterval(timer)
          if (success) {
            resolve('success')
          } else {
            resolve('fail')
          }
        }
      }, 500) // 轮询时间间隔
    })
  }
}
